package cn.witsky.rtp2ws.util;

import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.witsky.rtp2ws.Server;
import cn.witsky.rtp2ws.cache.CallManager;
import cn.witsky.rtp2ws.client.redis.RedisClient;
import cn.witsky.rtp2ws.domain.BaseCall;
import cn.witsky.rtp2ws.domain.CallInfo;
import cn.witsky.rtp2ws.exception.StartUpException;
import io.netty.util.internal.StringUtil;
import net.sf.json.JSONObject;

public class RedisUtil {
	private static Logger logger = LoggerFactory.getLogger(RedisUtil.class);

	//设置callid和rtp2ws的绑定关系 1.""表示设置关系出现异常 2."0"表示设置成功 3."1"表示已经被设置，且rtp2ws是同一个 4."-1"表示已经被设置，且rtp2ws是不同的
	public static String setRelation(String callId){
		try {
			String[] params = new String[3];
			params[0] = RedisKey.getRelationKey();
			params[1] = callId;
			params[2] = Server.ServerName;			
			StringBuilder luaScript = new StringBuilder("");
			luaScript.append("	local relationKey= ARGV[1];");
			luaScript.append("	local callId= ARGV[2];");
			luaScript.append("	local rtp2wsId= ARGV[3];");
			luaScript.append("	local oldRtp2wsId = redis.call('HGET',relationKey,callId);");
			luaScript.append("	if(not oldRtp2wsId) then ");
			luaScript.append("		redis.call('HSET', relationKey, callId, rtp2wsId);");		
			luaScript.append("		return '0';");
			luaScript.append("	elseif(oldRtp2wsId==rtp2wsId) then ");
			luaScript.append("		return '1';");			
			luaScript.append("	else");	
			luaScript.append("		return '-1';");
			luaScript.append("	end");
			Object result = RedisClient.execLuaScript(luaScript.toString(), String.class, params);
			return result.toString();
		}catch(Exception ex) {
			logger.error("设置call:"+callId+"和rtp2ws:"+Server.ServerName+"关系出现异常",ex);
			return "";
		}
	}
	
	public static String getRelation(String callId){
		try {
			return RedisClient.hget(RedisKey.getRelationKey(), callId).toString();
		}catch(Exception ex) {
			logger.error("获取call:"+callId+"绑定的rtp2ws出现异常",ex);
			return "";
		}
	}
	public static void clearRelation(String callId){
		try {
			RedisClient.hdel(RedisKey.getRelationKey(),callId);
		}catch(Exception ex) {
			logger.error("清理call:"+callId+"和rtp2ws绑定关系出现异常",ex);
		}
	}
	
	
	// 测试
	public static void test() throws StartUpException {
		try {
			logger.debug("测试。。。。。。。。。。。");
			String serverKey = RedisKey.getListKey();
			String[] params = new String[3];
			params[0] = serverKey;
			params[1] = Server.ServerName;
			params[2] = Server.getHost();
			StringBuilder luaScript = new StringBuilder("");
			luaScript.append("	local oldVal;");
			luaScript.append("	if(not oldVal) then ");
			luaScript.append("		return 0;");
			luaScript.append("	else ");
			luaScript.append("		return -1;");
			luaScript.append("	end");
			Object result = RedisClient.execLuaScript(luaScript.toString(), Long.class, params);
			logger.debug("test result:{}", result);
		} catch (Exception ex) {
			throw new StartUpException("redis连接异常。。。。。。。。。。");
		}

	}

	// 校验serverId，并上线
	public static Integer onLine() {
		try {
			logger.info("Rtp2Ws server:{} 上线了", Server.ServerName);
			String serverKey = RedisKey.getListKey();
			String[] params = new String[3];
			params[0] = serverKey;
			params[1] = Server.ServerName;
			params[2] = Server.getHost();
			StringBuilder luaScript = new StringBuilder("");
			luaScript.append("	local serverKey = ARGV[1];");
			luaScript.append("	local field = ARGV[2];");
			luaScript.append("	local val = ARGV[3];");
			luaScript.append("	local oldVal = redis.call('hget', serverKey,field);");
			luaScript.append("	if(not oldVal) then ");
			luaScript.append("		redis.call('hset', serverKey,field,val);");
			luaScript.append("		return 0;");
			luaScript.append("	elseif(oldVal==val) then ");
			luaScript.append("		return 0;");
			luaScript.append("	else ");
			luaScript.append("		return -1;");
			luaScript.append("	end");
			Object result = RedisClient.execLuaScript(luaScript.toString(), Long.class, params);
			if (result != null) {
				return Integer.parseInt(result.toString());
			} else {
				return -1;
			}
		} catch (Exception ex) {
			logger.error("Rtp2Ws server:" + Server.ServerName + "上线出现异常:", ex);
			return -1;
		}
	}

	// 离线
	public static void offLine() {
		try {
			logger.debug("Rtp2Ws server:{} 离线了", Server.ServerName);
			String serverKey = RedisKey.getListKey();
			RedisClient.hdel(serverKey, Server.ServerName);
		} catch (Exception ex) {
			logger.error("Rtp2Ws server:" + Server.ServerName + "离线出现异常:", ex);
		}

	}

	// 清理端口
	public static void clearPort() {
		try {
			logger.debug("Rtp2Ws server:{} 清理所有的udp端口", Server.ServerName);
			String key = RedisKey.getUdpListKey();
			RedisClient.del(key);
		} catch (Exception ex) {
			logger.error("清理udp端口出现异常:", ex);
		}
	}

	// 初始化端口
	public static void addUdpPort(int udpPort) {
		try {
			logger.debug("Rtp2Ws server:{} 增加资源udp端口:{}", Server.ServerName, udpPort);
			String key = RedisKey.getUdpListKey();
			RedisClient.rpush(key, udpPort + "");
		} catch (Exception ex) {
			logger.error("增加资源udp端口出现异常:", ex);
		}
	}

	// 存储会话信息
	public static boolean setCallInfo(BaseCall call) {
		boolean isSuc=false;
		try {
			String key = RedisKey.getCallListKey();
			RedisClient.hset(key, call.getCallId(), call.toJsonString());
			isSuc=true;
		} catch (Exception ex) {
			logger.error("更新call:" + call.getCallId() + "呼叫信息异常:", ex);
		}
		return isSuc;
	}

	//清理会话信息
	public static void clearCallInfo(BaseCall call) {
		try {
			RedisClient.hdel(RedisKey.getCallListKey(), call.getCallId());	
			clearRelation(call.getCallId());
		}catch(Exception ex) {
			logger.error("清理call:" + call.getCallId() + "呼叫信息异常:", ex);
		}

	}
	// 获取会话信息
	public static CallInfo getCallInfo(String callId) {
		try {
			String key = RedisKey.getCallListKey();
			Object obj=RedisClient.hget(key, callId);
			String val ="";
			if(obj!=null) {
				val=obj+"";
			}
			if (!StringUtil.isNullOrEmpty(val)) {
				JSONObject callJson = JSONObject.fromObject(val);
				return CallManager.createCallInfo(callJson);
			} else {
				return null;
			}
		} catch (Exception ex) {
			logger.error("读取call:" + callId + "呼叫信息异常:", ex);
			return null;
		}

	}
	// 获取会话信息
	public static CallInfo getCallInfo(String callId,String rtp2wsName) {
		try {
			String key = RedisKey.getCallListKey(rtp2wsName);
			Object obj=RedisClient.hget(key, callId);
			String val ="";
			if(obj!=null) {
				val=obj+"";
			}
			if (!StringUtil.isNullOrEmpty(val)) {
				JSONObject callJson = JSONObject.fromObject(val);
				return CallManager.createCallInfo(callJson);
			} else {
				return null;
			}
		} catch (Exception ex) {
			logger.error("读取call:" + callId + "呼叫信息异常:", ex);
			return null;
		}

	}
	// 给会话绑定udp端口
	public static Integer getUdpPort(String callId) {
		try {
			String udpListKey = RedisKey.getUdpListKey();
			String callPortHashKey = RedisKey.getBindPortKey();
			String[] params = new String[4];
			params[0] = callId;
			params[1] = Server.ServerName;
			params[2] = udpListKey;
			params[3] = callPortHashKey;
			StringBuilder luaScript = new StringBuilder("");
			luaScript.append("	local callId = ARGV[1];");
			luaScript.append("	local serverId = ARGV[2];");
			luaScript.append("	local udpListKey = ARGV[3];");
			luaScript.append("	local callPortHashKey = ARGV[4];");
			luaScript.append("	local udpPort = redis.call('lpop', udpListKey);");
			luaScript.append("	if(not udpPort) then ");
			luaScript.append("		return -1;");
			luaScript.append("	else ");
			luaScript.append("		redis.call('hset', callPortHashKey,callId,udpPort);");
			luaScript.append("		return tonumber(udpPort);");
			luaScript.append("	end ");
			Object result = RedisClient.execLuaScript(luaScript.toString(), Long.class, params);
			if (result != null) {
				return Integer.parseInt(result.toString());
			} else {
				return -1;
			}
		} catch (Exception ex) {
			logger.error("call:" + callId + "绑定端口出现异常:", ex);
			return -1;
		}
	}

	// 释放udp端口
	public static Integer freeUdpPort(String callId) {
		try {
			String udpListKey = RedisKey.getUdpListKey();
			String callPortHashKey = RedisKey.getBindPortKey();
			String relationKey=RedisKey.getRelationKey();
			String[] params = new String[5];
			params[0] = callId;
			params[1] = Server.ServerName;
			params[2] = udpListKey;
			params[3] = callPortHashKey;
			params[4] =relationKey;
			StringBuilder luaScript = new StringBuilder("");
			luaScript.append("	local callId = ARGV[1];");
			luaScript.append("	local serverId = ARGV[2];");
			luaScript.append("	local udpListKey = ARGV[3];");
			luaScript.append("	local callPortHashKey = ARGV[4];");
			luaScript.append("	local relationKey = ARGV[5];");
			luaScript.append("	local udpPort=redis.call('hget', callPortHashKey,callId);");
			luaScript.append("	if(not udpPort) then ");
			luaScript.append("		return 0;");
			luaScript.append("	else ");
			luaScript.append("		redis.call('hdel', callPortHashKey,callId);");
			luaScript.append("		redis.call('hdel', relationKey,callId);");
			if(Server.reusePort) {
				luaScript.append("		redis.call('lpush', udpListKey,udpPort);");
			}else {
				luaScript.append("		redis.call('rpush', udpListKey,udpPort);");
			}
			luaScript.append("		return tonumber(udpPort);");
			luaScript.append("	end");
			Object result = RedisClient.execLuaScript(luaScript.toString(), Long.class, params);
			if (result != null) {
				return Integer.parseInt(result.toString());
			} else {
				return -1;
			}
		} catch (Exception ex) {
			logger.error("释放call:" + callId + "的端口出现异常:", ex);
			return -1;
		}

	}

	// 获取会话和端口映射的集合
	public static Map<Object, Object> loadBind() {
		try {
			String callPortHashKey = RedisKey.getBindPortKey();
			return RedisClient.hgetAll(callPortHashKey);
		} catch (Exception ex) {
			logger.error("初始化绑定信息出现异常:", ex);
			return null;
		}		
	}
	public static Map<Object, Object> loadCall() {
		try {
			String callListKey = RedisKey.getCallListKey();
			return RedisClient.hgetAll(callListKey);
		} catch (Exception ex) {
			logger.error("初始化绑定信息出现异常:", ex);
			return null;
		}		
	}
	
	public static boolean backUpCallInfo(BaseCall call){
		boolean isSuc=false;
		try {
			String key = RedisKey.getCallBackUpKey(call.getCallId());
			RedisClient.set(key, call.toJsonString(), 7, TimeUnit.DAYS);
			isSuc=true;
		} catch (Exception ex) {
			logger.error("更新call:" + call.getCallId() + "呼叫信息异常:", ex);
		}
		return isSuc;
	}
	
	// 获取会话信息
		public static CallInfo getBackUpCallInfo(String callId) {
			try {
				String key = RedisKey.getCallBackUpKey(callId);
				Object obj=RedisClient.get(key);
				String val ="";
				if(obj!=null) {
					val=obj+"";
				}
				if (!StringUtil.isNullOrEmpty(val)) {
					JSONObject callJson = JSONObject.fromObject(val);
					return CallManager.createCallInfo(callJson);
				} else {
					return null;
				}
			} catch (Exception ex) {
				logger.error("读取call:" + callId + "呼叫信息异常:", ex);
				return null;
			}
		}
}
